from typing import Any, Final, TypeAlias

from .property import Property

ReasonType: TypeAlias = Any
class Account:
    def __init__(self, balance: int = 0) -> None:
        self._balance: int = 0
        if balance < 0:
            self.decrease(-balance, "Initial Debt")
        elif balance > 0: 
            self.increase(balance, "Initial Balance")
    
    def increase(self, amount: int, reason: ReasonType = None) -> None:
        self._balance += amount
    
    def decrease(self, amount: int, reason: ReasonType = None) -> None:
        self._balance -= amount
    
    @property
    def balance(self) -> int:
        return self._balance
    
    def __repr__(self) -> str:
        return object.__repr__(self) \
                .replace("object", f"object [balance={self.balance}]")

class Debt(Account):
    def __init__(self, balance: int = 0, interest_rate: float = 0) -> None:
        super().__init__(balance)
        self._interest_rate: Final[float] = interest_rate

    def update(self) -> None:
        self.increase(round(self._balance * self._interest_rate), "Interest")
    
    def __repr__(self) -> str:
        return object.__repr__(self) \
                .replace("object", f"object [balance={self.balance}, interest_rate={self._interest_rate*100:.2f}%]")

class Mortgage(Account):
    def __init__(self, property: Property, interest_rate: float = 0, life: int = 0) -> None:
        self.property: Final[Property] = property
        if self.property.mortgagable():
            self._balance = round(-property.value * (1 + interest_rate))
            self._life: int = life
            self.property.mortgage()
            self._paied_back: bool = False
        else:
            self._balance = 0
            self._life: int = 0
            self._paied_back: bool = True
    
    def increase(self, amount: int, reason: Any = None) -> None:
        raise NotImplemented
    
    def decrease(self, amount: int, reason: Any = None) -> None:
        raise NotImplemented
    
    def payback(self) -> None:
        self.property.redeem()
        self._life = 0
        self._paied_back = True
    
    @property
    def removable(self) -> bool:
        return self._life <= 0
    
    def onremove(self) -> None:
        if not self._paied_back:
            self.property.sell()
        
    def update(self) -> None:
        self._life -= 1
    
    def __repr__(self) -> str:
        return object.__repr__(self) \
                .replace("object", f"object [balance={self.balance}, lifetime={self._life}, property={self.property}]")